from typing_extensions import Union, List
from datetime import datetime

from fastapi import Request
from sqlalchemy import select, insert, func

from core.database import db_session
from core.formclass import AutoSaveForm
from core.models import Board, Member, WriteBaseModel, BoardGood, AutoSave
from core.exception import JSONException
from lib.common import dynamic_create_write_table, get_unique_id
from lib.token import check_token
from api.v1.models.ajax import AutoSaveModel, responses


class AJAXService:
    """AJAX 处理请求的服务类“处理AJAX请求的服务类”"""

    responses = responses

    def __init__(
        self,
        request: Request,
        db: db_session,
    ):
        self.request = request
        self.db = db

    @classmethod
    async def async_init(
        cls,
        request: Request,
        db: db_session,
    ):
        instance = cls(request, db)
        return instance

    def validate_member(self, member: Member):
        """确定您的会员资格  验证是否为会员"""
        if not member:
            raise JSONException(status_code=403, message="登录后可用.")

    def validate_token(self, token: str):
        """令牌验证   验证令牌”"""
        if not check_token(self.request, token):
            raise JSONException(status_code=403, message="令牌无效.")

    def get_board(self, bo_table: str) -> Board:
        """检查公告板的存在   确认公告栏是否存在"""
        board = self.db.get(Board, bo_table)
        if not board:
            raise JSONException(status_code=403, message="这是一个不存在的公告板.")
        return board

    def validate_board_good_use(self, board: Board, type: str):
        """公告板推荐/检查是否使用非推荐功能   确认是否使用公告栏推荐/非推荐功能"""
        bo_use_type = getattr(board, f"bo_use_{type}", None)
        if bo_use_type is None:
            raise JSONException(status_code=403, message="错误 type 输入。. good 或 nogood仅可能.")
        if not bo_use_type:
            raise JSONException(status_code=403, message="此公告板不使用推荐功能.")

    def get_write(self, bo_table: str, wr_id: int) -> WriteBaseModel:
        """检查岗位是否存在   确认帖子是否存在"""
        write_model = dynamic_create_write_table(bo_table)
        write = self.db.get(write_model, wr_id)
        if not write:
            raise JSONException(status_code=404, message="这是一个不存在的帖子.")#  不存在的帖子。
        return write

    def validate_write_owner(self, write: WriteBaseModel, member: Member, type: str):
        """自己的文章好/不好"""
        type_str = "待定" if type == "good" else "非推荐"
        if write.mb_id == member.mb_id:
            raise JSONException(status_code=403, message=f"无法对自己的文章进行{type_str}.")

    def get_ajax_good_data(self, bo_table: str, write: WriteBaseModel) -> dict:
        """查看帖子中的推荐/非推荐数据"""
        result = {"good": 0, "nogood": 0}
        write_good_results = self.db.scalars(select(BoardGood).where(
            BoardGood.bo_table == bo_table, BoardGood.wr_id == write.wr_id
        ))
        for good_data in write_good_results:
            if good_data.bg_flag == "good":
                result["good"] += 1
            else:
                result["nogood"] += 1
        return result

    def get_ajax_good_result(self, bo_table: str, member: Member, write: WriteBaseModel, type: str) -> dict:
        """查看帖子中的推荐/非推荐数据"""  #查看反馈
        result = {"status": "success", "message": "", "good": 0, "nogood": 0}
        type_str = "待定" if type == "good" else "非推荐"
        type_attr = f"wr_{type}"  # 选择的类型
        type_attr_rev = "wr_good" if type == "nogood" else "wr_nogood"  # 相反类型
        good_query = select(BoardGood).where(
            BoardGood.bo_table == bo_table,
            BoardGood.wr_id == write.wr_id,
            BoardGood.mb_id == member.mb_id
        )
        good_data = self.db.scalars(good_query).first()
        if good_data:
            #如果推荐/不推荐的bg_flag与选择的类型相同，
            #删除数据+减少帖子的推荐/不推荐计数
            if good_data.bg_flag == type:
                self.db.delete(good_data)
                setattr(write, type_attr, getattr(write, type_attr) - 1)
                self.db.commit()
                result["status"] = "cancel"
                result["message"] = f"{type_str}此操作已取消."
                #存在，如果是其他类型的话
                #修改数据+增加帖子的推荐/不推荐计数+减少反对类型计数
            else:
                good_data.bg_flag = type
                setattr(write, type_attr, getattr(write, type_attr) + 1)
                setattr(write, type_attr_rev, getattr(write, type_attr_rev) - 1)
                self.db.commit()
                result["message"] = f"post {type_str} 我做到了.."
        else:
        #如果不存在
        #添加数据+增加帖子的推荐/不推荐计数
            self.db.execute(
                insert(BoardGood).values(
                    bo_table=bo_table,
                    wr_id=write.wr_id,
                    mb_id=member.mb_id,
                    bg_flag=type
                )
            )
            setattr(write, type_attr, getattr(write, type_attr) + 1)
            self.db.commit()
            result["message"] = f"post {type_str} 我做到了.."

        #查看帖子的推荐/非推荐计数        
        self.db.refresh(write)
        result["good"] = write.wr_good
        result["nogood"] = write.wr_nogood
        return result

    def validate_login(self, member: Member):
        """验证您的登录"""
        if not member:
            raise JSONException(status_code=403, message="登录后可用.")

    def get_autosave_list(self, member: Member) -> List[AutoSave]:
        """返回自动保存列表。"""
        save_list = self.db.scalars(
            select(AutoSave)
            .where(AutoSave.mb_id == member.mb_id)
            .order_by(AutoSave.as_datetime.desc())
        ).all()
        return save_list

    def get_autosave_content(self, as_id: int, member: Member) -> AutoSave:
        """返回自动存储数据."""
        save_data = self.db.get(AutoSave, as_id)
        if not save_data:
            raise JSONException(status_code=404, message="无已保存的写入.")
        if save_data.mb_id != member.mb_id:
            raise JSONException(status_code=403, message="无法访问.")
        return save_data

    def get_autosave_count(self, mb_id: str) -> int:
        """返回自动存储的数量."""
        count = self.db.scalar(
            select(func.count(AutoSave.as_id))
            .where(AutoSave.mb_id == mb_id)
        )
        return count

    def autosave_save(self, member: Member, data: Union[AutoSaveForm, AutoSaveModel]):
        """验证并修改或添加临时存储数据"""
        if not data.as_uid:
            data.as_uid = get_unique_id(self.request)

        save_data = self.db.scalar(
            select(AutoSave).where(AutoSave.as_uid == data.as_uid)
        )
        if save_data:
            if save_data.mb_id != member.mb_id:
                raise JSONException(status_code=403, message="无法访问.")
            save_data.as_subject = data.as_subject
            save_data.as_content = data.as_content
            save_data.as_datetime = datetime.now()
        else:
            self.db.add(AutoSave(mb_id=member.mb_id, **data.__dict__))
        self.db.commit()

    def autosave_delete(self, as_id: int, member: Member):
        """删除临时存储"""
        save_data = self.db.get(AutoSave, as_id)
        if not save_data:
            raise JSONException(status_code=404, message="无已保存的写入.")
        if save_data.mb_id != member.mb_id:
            raise JSONException(status_code=403, message="无法访问.")
        self.db.delete(save_data)
        self.db.commit()